﻿var common = new Object();
common.validator = new Object();
function getStringFormatPlaceHolderRegEx(placeHolderIndex) {
    return new RegExp('({)?\\{' + placeHolderIndex + '\\}(?!})', 'gm')
}

function cleanStringFormatResult(txt) {
    if (txt == null) return "";

    return txt.replace(getStringFormatPlaceHolderRegEx("\\d+"), "");
}

String.format = function () {
    var s = arguments[0];
    if (s == null) return "";
    for (var i = 0; i < arguments.length - 1; i++) {
        var reg = getStringFormatPlaceHolderRegEx(i);
        s = s.replace(reg, (arguments[i + 1] == null ? "" : arguments[i + 1]));
    }
    return cleanStringFormatResult(s);
}


/*******************
 * Creator: 
 * Created date: 
 * Version : beta
 * 
 * Required: jQuery
 * 
 * Example:
 * 
 *******************
 * Description: tự động validate và hiển thị thông báo lỗi các element có gắn attribute validator
 *
 * Params: o: những thiết lập ban đầu cho validator
 * o.formID (string) : element bao các element cần validate (có thể là form, div, table)
 * o.errorID (string): id của (<ul>) vùng hiển thị lỗi. Nếu ko gán o.errorID thì text lỗi sẽ được show ngay cạnh được element validate
 * o.clientValidate (function): function validate trên js
 * o.serverValidate (object): validate trên server
 * o.autoScrollToError (boolean): tự động scroll lên vùng hiển thị lỗi khi có lỗi
 * 		= false: không scroll
 * 		= true (default): tự động scroll
 * o.disabledLoading (boolean): tự động khi validate sẽ show loading, nếu ko muốn show loading thì set disabledLoading = true. (default = false)
 * 
 * 
 * o.message (object): dùng để customize message thông báo lỗi
 * 	Example for o.message:
 * 		{
 * 			required: "{0} is required",
 * 			space: "{0} is not correct",
 * 			number: "{0} must be number",
 * 			...
 * 		}
 * 
 * Attribute validator:
 * 	- required : yêu cầu nhập liệu
 *  - space    : yêu cầu ko được nhập chỉ toàn space hoặc enter
 *  - number   : yêu cầu nhập số
 *  - min	   : check giá trị min 
 *  - max	   : check giá trị max
 *  - minmax   : check giá trị min và max		
 *  - maxlength: check max length
 *  - minlength: check min length
 *  - minmaxlength: check min và max length
 *  - alphabet : check chỉ nhập các ký tự alphabet		
 *  - email	   : check email hợp lệ
 *  - decimal  : check chỉ nhập số thập phân (nếu có dấu thập phân thì nhập tối đa = maxlength, ngược lại chỉ nhập tối đa = maxlength-3. sau số thập phân chỉ được nhập tối đa 2 số)
 */
common.validator = function(o, f)
{
	this.errors = [];
	this.o = o;
	this.t = {};
	this.waiting = false;
	this.showing = false;
	this.message = {};
	
	this.init = function()
	{
		if(typeof(o.autoScrollToError) == "undefined") this.o.autoScrollToError = true;
		if(typeof(this.o.errorID) == "undefined") this.o.errorID = "";
		if(typeof(this.o.disabledLoading) == "undefined") this.o.disabledLoading = false;
		
		var msg = o.message || {};
		
		this.message.required = msg.required || "msg_required";
		this.message.space = msg.space || "msg_trim_space_tab_enter";
		this.message.number = msg.number || "msg_required_only_number";
		this.message.min = msg.min || "msg_required_min_number";
		this.message.max = msg.max || "msg_required_max_number";
		this.message.minmax = msg.minmax || "";
		this.message.maxlength = msg.maxlength || "msg_required_max_length";
		this.message.minlength = msg.minlength || "msg_required_min_length";
		this.message.minmaxlength = msg.minmaxlength || "msg_required_over_max_length";
		this.message.alphabet = msg.alphabet || "msg_only_character";
		this.message.email = msg.email || "msg_email_correct";
	}
	
	/* Function: validate()
	 * Description: thực hiện validate
	 * Return: 
	 * 		false: có lỗi
	 * 		true: không có lỗi
	 */
	
	
	this.validate = function(o)
	{
		var _this = this;
		var t = this.t;
		this.errors = [];
		
		$("[validator]", "#" + this.o.formID).each(function(index, item)
		{
			var valid_list =  $(this).attr("validator").split(' ');
			_this.t = $(this);
			
			for(var i=0; i< valid_list.length; i++)
			{
				switch(valid_list[i].toLowerCase())
				{
					case "required":
						_this.checkRequired();
						break;
						
					case "space":
						_this.checkSpaceEnter();
						break;
						
					case "maxlength":
						_this.checkMaxLength();
						break;
					
					case "minlength":
						_this.checkMinLength();
						break;
						
					case "minmaxlength":
						_this.checkMinMaxLength();
						break;
						
					case "alphabet":
						_this.checkOnlyCharacter();
						break;
					case "number":
						_this.checkIsNumber();
						break;
					
					case "max":
						_this.checkMaxNumber();
						break;
					
					case "min":
						_this.checkMinNumber();
						break;
					
					case "minmax":
						_this.checkMinMaxNumber();
						break;
						
					case "email":
						_this.checkEmail();
						break;
						
					case "decimal":
						_this.checkIsDecimal();
						break;
				}
			}
		});
		
		if(typeof(this.o.clientValidate) == "function") 
		{
			this.o.clientValidate();
		}
		
		if(typeof(this.o.serverValidate) == "object") 
		{
			this.validateServer();
		}
		
		if(this.errors.length > 0)
		{
			return false;
		}
		else
		{
			return true;
		}
	}
	
	this.getElValue = function(t)
	{
		var _v = t.val(); 
		
		if(/ckeditor/.test(t.attr("validator")))
		{
			 _v = CKEDITOR.instances[t[0].id].getData();
		}
		
		return _v;
	}
	
	/**** 
	 * Hiển thị lỗi và tô đỏ các element bị lỗi
	 * Các lỗi sẽ append vào o.errorID
	 ****/
	this.showErrors = function()
	{
		var str = "";
		var o = null;
		
		this.showing = true;
		
		if(!this.waiting)
		{
			this.clear();
			
			if(this.errors.length > 0)
			{	
				for(var i=0; i<this.errors.length; i++)
				{
					o = this.errors[i];
					$("#" + o.id).addClass("input-error");
					$("[validatorid='" + o.id + "']").addClass("input-error");
					
					if(this.o.errorID == "")
					{
						var _vid = typeof($("#" + o.id).attr("validatorid")) == "undefined" ? "" : $("#" + o.id).attr("validatorid");
						
						if(_vid != "" )
						{
							$("#msg_" + _vid).addClass("error");
							$("#msg_" + _vid).html(o.text);
						}
						else
						{
							if(document.getElementById("msg_" + o.id) == null)
							{
								$("#" + o.id).after("<div class='error' gen='true'>" + o.text + "</div>");
							}
							else
							{
								$("#msg_" + o.id).addClass("error");
								$("#msg_" + o.id).html(o.text);
							}
						}
					}
					else
					{
						str += String.format("<li>{0}</li>", o.text);
					}
				}
				
				if(this.o.autoScrollToError) $.scrollTo('#' + this.errors[0].id);
			}
			
			if(this.o.errorID != "")
			{
				$("#" + this.o.errorID).append(str);
				$("#" + this.o.errorID).show();
				
				this.showing = false;
				if(this.o.autoScrollToError) $.scrollTo('#' + this.o.errorID);
			}
		}
	}
	
	/* Add thêm lỗi
	 * e: là object có cấu trúc
	 *		{ 
	 *			id: "id của element bị lỗi",
	 *			text: "Câu thông báo lỗi"
	 *		}
	 */
	this.addError = function(e)
	{
		this.errors.push(e);
	}
	
	/* Kiểm tra sau khi gọi validate(), có lỗi hay không
	 * Params: 
	 * 		id = null : sẽ kiểm tra có lỗi hay không trên toàn form
	 * 		   = 'element_id': sẽ kiểm tra element_id có bị lỗi hay không	
	 */
	this.hasError = function(id)
	{
		if(id)
		{
			for(var i=0;i<this.errors.length; i++)
			{
				if(id == this.errors[i].id) return true;
			}
		}
		else
		{
			if(this.errors.length > 0) return true;
		}
		
		return false;
	}
	
	this.hasRequired = function(o)
	{
		if(typeof(o) == "object")
		{
			var l = o.attr("validator").split(' ');
			for(var i=0; i<l.length; i++)
			{
				if(l[i] == "required")
				{
					return true;
				}
			}
		}
		
		return false;
	}
	
	this.checkRequired = function()
	{
		var t = this.t;
		var _v = this.getElValue(t); 				
		
		if(_v == "" || /watermarkCss/.test(t.attr("class")))
		{
			this.errors.push({
					id : t.attr("id"),
					text : String.format(this.message.required, t.attr("elname") || "" )
				});						
		}
	} 
	this.checkSpaceEnter = function()
	{
		var t = this.t;
		
		if(!this.hasRequired(t) && t.val() == "") return true;
		
		if(this.hasError(t.attr("id"))) return true;
		
		if(t.val().search(/[^ |　|\t]/) == -1){
			this.errors.push({
					id : t.attr("id"),
					text : String.format(this.message.space, t.attr("elname") || "" )
				});
		}
	}
	
	this.checkMaxLength = function()
	{
		var t = this.t;
		var maxlength = t.attr("maxlength"); 
		
		if((!this.hasRequired(t) && t.val() == "") || maxlength == "" || isNaN(maxlength) ) return true;
		
		if(this.hasError(t.attr("id"))) return true;
		
		if(t.val().length > Number(maxlength))
		{
			this.errors.push({
				id : t.attr("id"),
				text: String.format(this.message.maxlength, t.attr("elname") || "" )
			});
		}
	}
	
	this.checkMinLength = function()
	{
		var t = this.t;
		var minlength = t.attr("minlength"); 
		
		if((!this.hasRequired(t) && t.val() == "") || minlength == "" || isNaN(minlength)) return true;
		
		if(this.hasError(t.attr("id"))) return true;
		
		if(t.val().length < Number(minlength))
		{
			this.errors.push({
				id : t.attr("id"),
				text: String.format(this.message.minlength, t.attr("elname") || "", minlength )
			});
		}
	}
	
	this.checkMinMaxLength = function()
	{
		var t = this.t;
		
		var minlength = t.attr("minlength");
		var maxlength = t.attr("maxlength");
		
		if((!this.hasRequired(t) && t.val() == "") || minlength == "" || isNaN(minlength) || maxlength == "" || isNaN(maxlength)) return true;
		
		if(this.hasError(t.attr("id"))) return true;
		
		if(t.val().length < Number(minlength) || t.val().length > Number(maxlength))
		{
			this.errors.push({
				id : t.attr("id"),
				text : String.format(this.message.minmaxlength, t.attr("elname") || "", minlength, maxlength )
			});
		}
	}
	
	this.checkIsNumber = function()
	{
		var t = this.t;
		if(!this.hasRequired(t) && t.val() == "") return true;
		if(this.hasError(t.attr("id"))) return true;
		
		var regex = /^[0-9]+$/;
		if(!regex.test(t.val()))
		{
			this.errors.push({
				id : t.attr("id"),
				text: String.format(this.message.number, t.attr("elname") || "" )
			});
		}
	}
	
	this.checkMaxNumber = function()
	{
		var t = this.t;
		var max = t.attr("max");
		
		if(this.hasError(t.attr("id"))) return true;
		
		if((!this.hasRequired(t) && t.val() == "") || max == "" || isNaN(max)) return true;
		
		if(Number(t.val()) > Number(max))
		{
			this.errors.push({
				id : t.attr("id"),
				text: String.format(this.message.max, t.attr("elname") || "", max )
			});
		}
	}
	
	this.checkMinNumber = function()
	{
		var t = this.t;
		var min = t.attr("min");
		
		if(this.hasError(t.attr("id"))) return true;
			
		if((!this.hasRequired(t) && t.val() == "") || min == "" || isNaN(min)) return true;
		
		if(Number(t.val()) < Number(min))
		{
			this.errors.push({
				id : t.attr("id"),
				text: String.format(this.message.min, t.attr("elname") || "", min )
			});
		}
	}
	
	this.checkMinMaxNumber = function()
	{
		var t = this.t;
		var min = t.attr("min");
		var max = t.attr("max");
		
		if(this.hasError(t.attr("id"))) return true;
			
		if((!this.hasRequired(t) && t.val() == "") || min == "" || isNaN(min) || max == "" || isNaN(max) ) return true;
		
		if(Number(t.val()) < Number(min) || Number(t.val()) > Number(max))
		{
			this.errors.push({
				id : t.attr("id"),
				text: String.format(this.message.minmax, t.attr("elname") || "", min, max )
			});
		}
	}
	
	this.checkOnlyCharacter = function()
	{
		var t = this.t;
		var _v = this.getElValue(t);
		
		if(this.hasError(t.attr("id"))) return true;
		
		var regex = /^[A-Za-z]+$/;
		if(!regex.test(_v))
		{
			this.errors.push({
				id : t.attr("id"),
				text: String.format(this.message.alphabet, t.attr("elname") || "" )
			});
		}
	}

	
	this.checkEmail = function()
	{
		var t = this.t; 
		
		if(this.hasError(t.attr("id"))) return true;
		if(t.val() == "") return true;
		
		var regex = /^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/;
		if(!regex.test(t.val()))
		{
			this.errors.push({
				id : t.attr("id"),
				text: String.format(this.message.email, t.attr("elname") || "" )
			});
		}
	}
	
	this.checkIsDecimal = function()
	{
		var error = "msg_required_only_number";
		var t = this.t;
		isValid = true;
		
		  if(t.val() == '')
		  {
		      isValid = true;
		  }
		  else
		  {
			  if(isNaN(t.val()))
				  isValid = false;
			  else
			  {
				  if(t.val().indexOf(".") > -1)
				  {
						  if(t.val().length - (t.val().indexOf('.')+1) > 2){
							  isValid = false;
							  error = 'notice82';
						  }
					      else {
							  isValid = true;
					      }
				  }
				  else
				  {
					  	if (t.attr("maxlength") > 0 && (t.val().length > (t.attr("maxlength")- 3)))
						  	isValid = false;
					  	else {
				  		 	isValid = true;
					  }
				  }
		      }
		  }
		
		if(isValid == false)
		{
			this.errors.push({
				id : t.attr("id"),
				text: String.format(error, t.attr("elname") || "" )
			});
		}
	}
	
	this.validateServer = function()
	{
		var o = this.o.serverValidate;
		
		if(typeof(o.success) != "function") return;
		
		var _this = this;
		
		var t = o.paramIDs;
		var params = {};
		
		for(var i=0; i< t.length; i++)
		{
			if(!this.hasError(t[i]))
			{
				params[t[i]] = $("#" + t[i]).val();
			}			
		}
		
		if(typeof(o.beforeSend) == "function")
		{
			if(o.beforeSend() == false) return;
		}
		
		this.waiting = true;
		
		$.ajax({
		  url: o.url,
		  data: params,
		  cache:false,
		  async:false,
		  type: 'post',
		  success: function(data){
			  var result = data;
				
				_this.waiting = false;
				
				o.success(result);
				if(_this.showing)
				{
					_this.showErrors();
				}
		  }
		});
	}
	
	/* 
	 * Clear các lỗi và tô đỏ các element
	 */
	this.clear = function()
	{
		if(this.o.errorID == "")
		{
			$(".error", "#" + this.o.formID).html("");
			$(".input-error", "#" + this.o.formID).next("[gen='true']").remove();
		}
		else
		{
			$("#" + this.o.errorID).empty();
		}
		
		$(".input-error", "#" + this.o.formID).removeClass("input-error");
	}
	
	this.clearAllError = function()
	{
		this.errors = [];
	}
	
	// Init for constructer
	this.init();
}

common.validator.checkRequired = function(id)
{
	var t = $("#" + id);
	if(t.val() == "" || /watermarkCss/.test(t.attr("class")))
	{
		return false;
	}
	return true;
}
common.validator.checkIsNumber = function(id)
{
	var t = $("#" + id);
	if(t.val() == "") return true;
	var regex = /^[0-9]+$/;
	if(!regex.test(t.val()))
	{
		return false;
	}
	return true;
}
common.validator.checkSpaceEnter = function(id)
{
	var t = $("#" + id);
	
	if(t.val() == "") return true;	
	if(t.val().search(/[^ |　|\t]/) == -1){
		return false;
	}
	return true;
}

common.validator.getElValue = function(t)
{
	var _v = t.val(); 
	
	if(/ckeditor/.test(t.attr("validator")))
	{
		 _v = CKEDITOR.instances[t[0].id].getData();
	}
	
	return _v;
}
common.validator.checkMaxNumber = function(id, maxlength)
{
	var t = $("#" + id);
	var max = maxlength || 0;

	if((t.val() == "") || max == 0 || isNaN(max)) return true;
	
	if(t.val().length > max)
	{
		return false;
	}
	return true;
}
common.validator.checkEmail = function(id)
{
	var t = $("#" + id);
	
	var regex = /^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/;
	if(!regex.test(t.val()))
	{
		return false;
	}
	return true;
}
common.validator.is_valid_username = function(id){
	var t = $("#" + id);
	
	var regex = /^[A-Za-z0-9\_\-]+$/;
	if(!regex.test(t.val()))
	{
		return false;
	}
	return true;
}
common.validator.is_valid_password = function(id){
	var t = $("#" + id);
	
	var regex = /^[A-Za-z0-9\!\@\#\$\%\^\&\*\(\)\_\-]+$/;
	if(!regex.test(t.val()))
	{
		return false;
	}
	return true;
}